WA-CI-005: Fix MountPoint.unwrap_app to stop at Class objects (next CI regression)#746
Conversation
The unwrap_app helper introduced in PR #739 was recursively calling .app on Rails engine classes. Engine classes respond to .app (returning their routes), causing unwrap_app to traverse past the engine class and never return it. Result: MountPoint.find returned nil for all engines. Fix: add `return app if app.is_a?(Class)` guard before the .app delegation check. Engine classes are Class objects; the Constraints wrappers we want to peel are instances. This is compatible with Rails 6.1 and Rails 7. Fixes next-branch CI regression (broken since 2026-03-02 15:54 ET).
Wave 1 Review SummaryAll 4 Wave 1 reviewers have returned verdicts. Wave 1 gate: PASS ✅
architectureClean fix. Correct layer and scope — securityNo security implications. Pure control-flow guard on internal Rack middleware unwrapping utility. No new input handling, deserialization, or network calls. Existing depth guard retained. simplicitySingle guard clause addition — minimal surface area. Inline comment explains the non-obvious Class check clearly. Test is direct and minimal. Follows existing guard-then-recurse pattern exactly. rails-conventions (PASS_WITH_NOTES)Two LOW-severity documentation style nits — neither blocks merge:
Proceeding to Wave 2 (rails-security, database, test-quality). |
Wave 2 Review Results — All Passed ✅rails-security: PASS — Zero security surface; internal routing utility guard clause only. No user input, no auth, no views. database: PASS — No database-related changes in this PR. Pure Ruby routing utility only. test-quality: PASS_WITH_NOTES (LOW) — New regression test All Wave 2 reviewers passed. Proceeding to Wave 3 (performance, frontend, accessibility). |
Wave 3 Review Results — All PASS ✅performance ( accessibility ( frontend ( Wave 3 complete. Proceeding to Wave 4 (documentation). |
✅ All Review Waves PassedAll reviewers returned PASS or PASS_WITH_NOTES. This PR is merge-ready.
Documentation reviewer note: Docstring could be marginally more precise — Labeled |
Fixes the
nextbranch CI regression introduced by PR #739.Root Cause
MountPoint.unwrap_appcalled.apprecursively without checking whether the current object is a Class. Rails Engine classes respond to.app(returning their routes), sounwrap_apptraversed through the engine class and returned something deeper in the delegation chain — never the engine class itself.Result:
MountPoint.find(Workarea::Storefront::Engine)returnednil.Admin::StorefrontHelper#storefrontthen calledsend(nil)→nil is not a symbol nor a string— crashing every admin test that renders the application layout.Fix
Added
return app if app.is_a?(Class)at the top ofunwrap_app. Engine classes areClassobjects; theActionDispatch::Routing::Mapper::Constraintswrappers we want to peel are instances. This guard is backward-compatible with Rails 6.1 and Rails 7.Verification
MountPointtests passtest_unwrap_app_stops_at_classregression testnextafter mergeClient impact
None — internal routing utility. Behavior of
mount_pointhelper is restored to correct semantics.